package vn.bang.xiangqi.server.test;

import java.rmi.RemoteException;
import java.sql.SQLException;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource;

/**
 * Database utilities used for testing outside the J2ee container.
 */
public final class DatabaseUtilities {

	private static final Logger LOG = LoggerFactory
			.getLogger(DatabaseUtilities.class);
	private static final MysqlConnectionPoolDataSource DATASOURCE = new MysqlConnectionPoolDataSource();
	private static final String JNDI_ROOT = "java:jboss";
	private static final String DS_NAME = "mobilegames";
	private static final String JNDI_LOC = JNDI_ROOT + "/datasources";
	private static final String JNDI_NAME = JNDI_LOC + "/" + DS_NAME;
	private static final String USERNAME = "root";
	private static final String DB_NAME = "mobilegames";
	private static final String DB_SERVER = "localhost";
	private static final int DB_PORT = 3306;

	/**
	 * true utility class does not need to be instantiated.
	 */
	private DatabaseUtilities() {
	}

	/**
	 * per default uses org.apache.naming.java.javaURLContextFactory and
	 * prefixes packages with org.apache.naming.
	 * 
	 * @return new initial JNDI context
	 * @throws NamingException
	 *             when JNDI context could not be reached.
	 */
	private static InitialContext getContext() throws NamingException {

		// Do not override keys in the system if they are already set.
		if (System.getProperty(Context.INITIAL_CONTEXT_FACTORY) == null) {
			System.setProperty(Context.INITIAL_CONTEXT_FACTORY,
					"org.apache.naming.java.javaURLContextFactory");
		}
		if (System.getProperty(Context.URL_PKG_PREFIXES) == null) {
			System.setProperty(Context.URL_PKG_PREFIXES, "org.apache.naming");
		}
		return new InitialContext();
	}

	private static boolean exists(String jndi_name) throws NamingException {
		try {
			getContext().lookup(jndi_name);
		} catch (NameNotFoundException e) {
			return false;
		}
		return true;
	}

	/**
	 * Programatically creates a new datasource and binds fatasource to JNDI key
	 * JNDI_LOC
	 * 
	 * @throws NamingException
	 *             when the JNDI context could not be written to.
	 * @see #JNDI_LOC
	 */
	public static void createTestDataSource() throws NamingException {
		synchronized (DATASOURCE) {
			// check to see if we already initialized the datasource
			if (USERNAME.equals(DATASOURCE.getUser())) {
				return; // we already created a DATASOURCE. we can stop.
			}
			try {
				final InitialContext ctx = getContext();
				if (!exists(JNDI_ROOT)) {
					ctx.createSubcontext(JNDI_ROOT);
				} else {
					LOG.warn(
							JNDI_ROOT
									+ " JNDI context already bound to {}. Is Jboss running separately?",
							ctx.lookup(JNDI_ROOT));
				}
				if (!exists(JNDI_LOC)) {
					ctx.createSubcontext(JNDI_LOC);
				} else {
					LOG.warn(
							JNDI_LOC
									+ " already bound to {}. Is Jboss running separately?",
							ctx.lookup(JNDI_LOC));
				}
				if (!exists(JNDI_NAME)) {
					DATASOURCE.setServerName(DB_SERVER);
					DATASOURCE.setPort(DB_PORT);
					DATASOURCE.setDatabaseName(DB_NAME);
					DATASOURCE.setUser(USERNAME);
					DATASOURCE.setPassword("portfolio@");
					ctx.bind(JNDI_NAME, DATASOURCE);
				} else {
					LOG.debug("Datasource bound to {}:{}" + JNDI_NAME,
							InitialContext.doLookup(JNDI_NAME));
				}
			} catch (NamingException ne) {
				LOG.error("Unable to create test datasource: {}", ne);
				// force retry next call even when bind fails.
				removeTestDataSource();
			}
		}
	}

	/**
	 * un-binds the datasource from from JNDI key JNDI_LOC
	 * 
	 * @throws NamingException
	 *             when JNDI could not be written to
	 */
	public static void removeTestDataSource() {
		synchronized (DATASOURCE) {
			try {
				final Context ctx = getContext();
				if (exists(JNDI_NAME)) {
					ctx.unbind(JNDI_NAME);
				}
			} catch (NamingException ex) {
				LOG.error("Unable to unbind daatasource {} from JNDI",
						JNDI_NAME);
			} finally {
				// force invalidation of datasource
				DATASOURCE.setUser(null);
			}
		}
	}

	/**
	 * @param args
	 * @throws NamingException
	 * @throws RemoteException
	 * @throws SQLException
	 */
	public static void main(final String[] args) throws RemoteException,
			NamingException, SQLException {
		createTestDataSource();
		createTestDataSource();
		removeTestDataSource();
		/*
		 * EntityManager entityManager = Persistence.createEntityManagerFactory(
		 * Constants.PERSISTENCE_UNIT).createEntityManager();
		 * entityManager.getTransaction().begin(); Address address=new
		 * Address(); entityManager.persist(address);
		 * entityManager.getTransaction().commit();
		 */
	}

}
